

#ifndef UC_GEMAT3D_H
#define UC_GEMAT3D_H

#include "zgegbl.h"
#include "zgemat2d.h"
#include "zgepnt3d.h"
#pragma pack (push, 8)

class UcGeLine3d;
class UcGeVector3d;
class UcGePlane;
class UcGeTol;

class 
GE_DLLEXPIMPORT
UcGeMatrix3d
{
public:
    UcGeMatrix3d();
    UcGeMatrix3d(const UcGeMatrix3d& src);

    static const   UcGeMatrix3d    kIdentity;

    UcGeMatrix3d&  setToIdentity();

    UcGeMatrix3d   operator *      (const UcGeMatrix3d& mat) const;
    UcGeMatrix3d&  operator *=     (const UcGeMatrix3d& mat);
    UcGeMatrix3d&  preMultBy       (const UcGeMatrix3d& leftSide);
    UcGeMatrix3d&  postMultBy      (const UcGeMatrix3d& rightSide);
    UcGeMatrix3d&  setToProduct    (const UcGeMatrix3d& mat1, const UcGeMatrix3d& mat2);

    UcGeMatrix3d&  invert          ();
    UcGeMatrix3d   inverse         () const;

    ZSoft::Boolean isSingular      (const UcGeTol& tol = UcGeContext::gTol) const;

    UcGeMatrix3d&  transposeIt     ();
    UcGeMatrix3d   transpose       () const;

    bool operator ==     (const UcGeMatrix3d& mat) const;
    bool operator !=     (const UcGeMatrix3d& mat) const;
    bool isEqualTo       (const UcGeMatrix3d& mat, const UcGeTol& tol
                                    = UcGeContext::gTol) const;

    ZSoft::Boolean isUniScaledOrtho(const UcGeTol& tol = UcGeContext::gTol) const;
    ZSoft::Boolean isScaledOrtho   (const UcGeTol& tol = UcGeContext::gTol) const;

    double         det             () const;

    UcGeMatrix3d&  setTranslation  (const UcGeVector3d& vec);
    UcGeVector3d   translation     () const;

    UcGeMatrix3d&  setCoordSystem  (const UcGePoint3d& origin,
                                    const UcGeVector3d& xAxis,
                                    const UcGeVector3d& yAxis,
                                    const UcGeVector3d& zAxis);
    void           getCoordSystem  (UcGePoint3d& origin,
                                    UcGeVector3d& xAxis,
                                    UcGeVector3d& yAxis,
                                    UcGeVector3d& zAxis) const;

    UcGeMatrix3d&  setToTranslation(const UcGeVector3d& vec);
    UcGeMatrix3d&  setToRotation   (double angle, const UcGeVector3d& axis,
                                    const UcGePoint3d& center
                                    = UcGePoint3d::kOrigin);
    UcGeMatrix3d&  setToScaling    (double scaleAll, const UcGePoint3d& center
                                    = UcGePoint3d::kOrigin);
    UcGeMatrix3d&  setToMirroring  (const UcGePlane& pln);
    UcGeMatrix3d&  setToMirroring  (const UcGePoint3d& pnt);
    UcGeMatrix3d&  setToMirroring  (const UcGeLine3d& line);
    UcGeMatrix3d&  setToProjection (const UcGePlane& projectionPlane,
                                    const UcGeVector3d& projectDir);
    UcGeMatrix3d&  setToAlignCoordSys(const UcGePoint3d& fromOrigin,
                                    const UcGeVector3d& fromXAxis,
                                    const UcGeVector3d& fromYAxis,
                                    const UcGeVector3d& fromZAxis,
                                    const UcGePoint3d& toOrigin,
                                    const UcGeVector3d& toXAxis,
                                    const UcGeVector3d& toYAxis,
                                    const UcGeVector3d& toZAxis);

    UcGeMatrix3d&  setToWorldToPlane(const UcGeVector3d& normal);
    UcGeMatrix3d&  setToWorldToPlane(const UcGePlane& plane);
    UcGeMatrix3d&  setToPlaneToWorld(const UcGeVector3d& normal);
    UcGeMatrix3d&  setToPlaneToWorld(const UcGePlane& plane);

    static
    UcGeMatrix3d   translation     (const UcGeVector3d& vec);
    static
    UcGeMatrix3d   rotation        (double angle, const UcGeVector3d& axis,
                                    const UcGePoint3d& center
                                    = UcGePoint3d::kOrigin);
    static
    UcGeMatrix3d   scaling         (double scaleAll, const UcGePoint3d& center
                                    = UcGePoint3d::kOrigin);
    static
    UcGeMatrix3d   mirroring       (const UcGePlane& pln);
    static
    UcGeMatrix3d   mirroring       (const UcGePoint3d& pnt);
    static
    UcGeMatrix3d   mirroring       (const UcGeLine3d& line);
    static
    UcGeMatrix3d   projection      (const UcGePlane& projectionPlane,
                                    const UcGeVector3d& projectDir);
    static
    UcGeMatrix3d   alignCoordSys   (const UcGePoint3d&  fromOrigin,
                                    const UcGeVector3d& fromXAxis,
                                    const UcGeVector3d& fromYAxis,
                                    const UcGeVector3d& fromZAxis,
                                    const UcGePoint3d&  toOrigin,
                                    const UcGeVector3d& toXAxis,
                                    const UcGeVector3d& toYAxis,
                                    const UcGeVector3d& toZAxis);

    static
    UcGeMatrix3d   worldToPlane    (const UcGeVector3d& normal);
    static
    UcGeMatrix3d   worldToPlane    (const UcGePlane&);
    static
    UcGeMatrix3d   planeToWorld    (const UcGeVector3d& normal);
    static
    UcGeMatrix3d   planeToWorld    (const UcGePlane&);

	double scale(void) const;

    double          norm            () const;

    UcGeMatrix2d convertToLocal     (UcGeVector3d& normal, double& elev) const;

    double         operator ()     (unsigned int, unsigned int) const;
    double&        operator ()     (unsigned int, unsigned int);

    double         entry[4][4];    

    ZSoft::Boolean  inverse(UcGeMatrix3d& inv, double tol) const;

private:
    void           pivot           (int, UcGeMatrix3d&);
    int            pivotIndex(int) const;
    void           swapRows        (int, int, UcGeMatrix3d&);
};

ZSOFT_FORCE_INLINE bool
UcGeMatrix3d::operator == (const UcGeMatrix3d& otherMatrix) const
{
    return this->isEqualTo(otherMatrix);
}

ZSOFT_FORCE_INLINE bool
UcGeMatrix3d::operator != (const UcGeMatrix3d& otherMatrix) const
{
    return !this->isEqualTo(otherMatrix);
}

ZSOFT_FORCE_INLINE double
UcGeMatrix3d::operator () (
    unsigned int row,
    unsigned int column) const
{
    return entry[row][column];
}

ZSOFT_FORCE_INLINE double&
UcGeMatrix3d::operator () (
    unsigned int row,
    unsigned int column)
{
    return entry[row][column];
}

#pragma pack (pop)
#endif
